<?php
/* --------------------------------------------------------------
   LogfileService.php 2024-07-23
   Gambio GmbH
   http://www.gambio.de
   Copyright (c) 2018 Gambio GmbH
   Released under the GNU General Public License (Version 2)
   [http://www.gnu.org/licenses/gpl-2.0.html]
   --------------------------------------------------------------
*/

declare(strict_types=1);

namespace Gambio\Admin\Modules\Logfiles\Services;


use Doctrine\DBAL\Exception;
use Gambio\Admin\Modules\Logfiles\Interfaces\LogfileServiceInterface;
use Gambio\Admin\Modules\Logfiles\Repository\LogfileServiceRepository;
use Gambio\Core\Application\ValueObjects\Path;

class LogfileService implements LogfileServiceInterface
{

    /** @var array<int, string> $blacklist */
    private array $blacklist = [
      '.htaccess',
      'index.html',
    ];

    /** @var LogfileServiceRepository $repository */
    private LogfileServiceRepository $repository;

    /** @var Path $path */
    private Path $path;

    /** @var string $logfilesDir */
    private string $logfilesDir;

    /** @var int $threshold */
    private int $threshold;


    public function __construct(LogfileServiceRepository $repository, Path $path)
    {
        $this->repository = $repository;
        $this->path = $path;
        $this->logfilesDir = $this->path->getLogfilesDir();
        $this->saveDefaultConfig();
    }

    /**
     * @return array<string, array<int, string>>
     */
    public function deleteOldLogFiles(): array
    {
        $deleted = [];

        foreach (new \DirectoryIterator($this->logfilesDir) as $file) {
            /** @var \DirectoryIterator $file */
            if ($file->isDot() || $this->isBlacklisted($file) || $this->isNotDeprecated($file)) {
                continue;
            }
            $removed = @unlink($file->getPathname());
            if ($removed) {
                $deleted['deleted'][] = $file->getFilename();
            } else {
                $deleted['failed'][] = $file->getFilename();
            }
        }

        return $deleted;
    }


    /**
     * Get array of all log files
     *
     * @return array<int, array<string, string>>
     */
    public function getLogFiles(): array
    {
        $files = [];

        foreach (new \DirectoryIterator($this->logfilesDir) as $file) {
            /** @var \DirectoryIterator $file */
            if ($file->isDot()) continue;
            $tmpArray['fileName'] = $file->getFilename();
            $tmpArray['mtime'] = date('Y-m-d H:i:s', $file->getMTime());
            $files[] = $tmpArray;
        }

        return $files;
    }


    /**
     * Checks and returns true if given file is blacklisted.
     *
     * @param \DirectoryIterator $file File to be checked.
     *
     * @return bool True if file is blacklisted.
     */
    private function isBlacklisted(\DirectoryIterator $file): bool
    {
        return in_array($file->getFilename(), $this->blacklist);
    }


    /**
     * Checks and returns true if given file is NOT deprecated (Never than $threshold days).
     *
     * @param \DirectoryIterator $file File to be checked.
     * @return bool True if file is NOT deprecated.
     */
    private function isNotDeprecated(\DirectoryIterator $file): bool
    {
        return $file->getMTime() > strtotime('-' . $this->threshold . ' days');
    }

    /**
     *
     * @throws Exception
     * @return array<string,bool|int|null>
     */
    public function loadConfigFromDatabase(): array
    {
        return $this->repository->findConfiguration();
    }

    /**
     * @return void
     * @throws Exception
     */
    public function saveDefaultConfig(): void
    {
        $this->repository->saveConfiguration();
    }

    /**
     * @param array $cronJobDependencies
     * @return void
     */
    public function setDependencies(array $cronJobDependencies): void
    {
        if (empty($cronJobDependencies)) {
            return;
        }

        $this->threshold = $cronJobDependencies[0]->asInt();
        if ($cronJobDependencies[1] instanceof \ExistingDirectory) {
            $this->logfilesDir = $cronJobDependencies[1]->getAbsolutePath();
        }

        $this->blacklist = $cronJobDependencies[2];
    }

}